摘要
這篇文章主要探討了 大型語言模型 (LLM) 的自我完善技術,特別是 Self-Refine 的概念和實作方法。文章從介紹 Reflection Agents 的概念出發,解釋了它們如何透過 自我反思 來提升模型的輸出質量。接著,文章詳細闡述了 Self-Refine 的工作原理,包含三個核心步驟:問題識別、建議生成、上下文整合與程式碼重寫。
文章中還介紹了 Self-Refine 的 框架組成 和 實驗結果,證明了它在不同任務中相較於傳統方法的優勢。最後,文章使用 LangGraph 來實際示範如何實現 Self-Refine 技術,並深入探討了 迭代次數、模型能力 等影響因素。文章結尾提到了更進階的 Reflexion 技術,並展望了 LLM 自我完善技術的發展方向。
相比於過往單一 Workflow Agent 開發,當今人工智慧導入了 Agent 概念,可借助大型語言模型力量,對於程式運作尚有機會達到逐步改良的機會。如果在 Agent 當中加入自動回饋,好讓模型在步驟中對於自己的輸出進行一輪批判並且給予回應,那會如何呢?這就是為何需要 Reflection。
本文探討了 LLM 自我優化的基礎技術 Self-Refine。這是 AI 代理反思機制的入門級實現,為更進階的技術如 Reflexion 奠定了基礎。在後續的文章中,我們將深入探討 Reflexion 如何在 Self-Refine 的基礎上進一步提升 LLM 的自我完善能力。
Reflection Agents 是一種先進的 AI 代理,能夠對自身的輸出進行批判性分析和自我改進。這種機制使 AI 系統能夠像人類一樣,通過反思和迭代來不斷優化自己的表現。
一句話定義:Reflection 是一種提示策略,旨在提高 AI 代理和類似系統的輸出質量和成功率。
相較於傳統的單一 Workflow Agent 開發,Reflection Agents 利用大型語言模型(LLM)的強大能力,實現了程序運行的逐步改良。這種方法可以顯著改善 ChatGPT、Claude、Gemini 和 Llama 等模型的輸出質量。
Self-Refine 的第一步是讓 LLM 對自身的輸出進行批判性分析。這個過程中,LLM 不僅要識別潛在的問題,還要生成具體的改進建議。例如,對於一篇文章評論,LLM 可能會指出"情感傾向不夠明確"或"缺乏具體細節支撐觀點"等問題。這種自我批評的能力是 Self-Refine 技術的基石,為後續的優化提供了明確的方向。
在識別問題並生成建議後,Self-Refine 的下一步是將這些反饋與初始輸出整合為新的上下文。基於這一綜合信息,LLM 進行代碼或內容的重寫。這個過程不僅僅是簡單的修改,而是對整體內容進行深思熟慮的重構,以確保改進建議被有效地融入新的輸出中。
Self-Refine 的核心在於其迭代性。通過反覆執行問題識別、建議生成和內容重寫的步驟,LLM 能夠不斷提升輸出質量。研究表明,每次迭代都可能帶來顯著的性能提升,尤其是在初始幾輪迭代中。這種持續優化的過程使得 Self-Refine 在代碼生成、文本創作和問答系統等多個領域都展現出卓越的效果。
亮點:這種自我反思和迭代優化的過程,在代碼生成、文本創作和問答系統等多個領域都展現出卓越的效果,大大提升了 LLM 的實用性和可靠性。
讓我們深入探討 Self-Refine 的核心理念、工作原理和框架組成。
Self-Refine 是一種創新的 LLM (大型語言模型) 優化技術,通過迭代式自我回饋來提升模型在多樣化任務上的表現。這種方法無需額外的監督訓練數據或強化學習,僅依靠單一 LLM 即可實現。
一般來說,Self-Refine 在實作中會被稱為 Basic Reflection 技巧,但這邊還是希望大家心從源頭認識與了解核心重點。
Self-Refine 的工作原理基於三個關鍵步驟,形成一個完整的改善循環:
這三個步驟可以進行多輪迭代,每次迭代都有可能帶來顯著的性能提升。
關鍵優勢: 無需額外訓練,單一 LLM 即可完成全流程
Self-Refine 框架由三個主要組件構成,它們協同工作,形成一個強大的迭代改善循環:
FEEDBACK 模組:
REFINE 模組:
迭代機制:
這三個組件的緊密配合,使 Self-Refine 能夠不斷提升輸出質量,直至達到預期標準。框架的靈活性還允許根據具體任務需求進行調整,使其適用於各種不同的應用場景。
以下是 Self-Refine 框架的簡化 Python 實現示例:
def self_refine(prompt: str, max_iterations: int = 3) -> str:
def is_refinement_sufficient(prompt, feedback, initial, refined) -> bool:
# 實現任務特定的停止條件
pass
answer = ChatGPT(prompt) # 初始輸出生成
for _ in range(max_iterations):
feedback = ChatGPT(feedback_prompt, answer) # 生成回饋
refined = ChatGPT(refiner_prompt, feedback, answer) # 根據回饋優化
if is_refinement_sufficient(prompt, feedback, answer, refined):
break
answer = refined # 更新答案為優化後的版本
return refined
為了驗證 Self-Refine 的效果,研究者們設計了一系列全面的實驗。這些實驗旨在回答幾個關鍵問題:
研究者們選擇了 7 種不同類型的任務,包含:情感反轉(Sentiment Reversal)、對話回應生成(Dialogue Response Generation)、代碼優化(Code Optimization)、代碼可讀性改進(Code Readability Improvement)、數學推理(Math Reasoning)、首字母縮略詞生成(Acronym Generation)、約束生成(Constrained Generation)等7 個不同的任務進行了廣泛的實驗,證明Self-Refine 的性能優於GPT- 3.5 甚至GPT- 等強大生成器的直接生成。
image caption: 用於評估 SELF-REFINE 的任務概覽,包括相關數據集及其規模。對於每項任務,作者展示了一次迭代優化的過程,包括輸入 x
、先前生成的輸出 y_t
、生成的反饋 f_bt
,以及優化後的結果 y_t+1
。
實驗數據揭示,Self-Refine 技術在各種規模的模型上均表現出色:
這一現象表明,Self-Refine 有效釋放了更強大模型的潛力。
Self-Refine 技術的核心在於其三大步驟:FEEDBACK(回饋)、REFINE(優化)以及這兩個步驟的迭代循環。作者為當中步驟進行了些探討。
Self-Refine 的核心優勢之一是其迭代優化能力。研究團隊仔細探討了多輪 FEEDBACK-REFINE 迭代對性能的影響,得出了一些令人振奮的結果:
研究發現,雖然性能隨迭代次數增加而提升,但存在邊際效應遞減的現象。值得注意的是,在多方面回饋任務(如首字母縮略詞生成)中,性能可能不會單調增加,這凸顯了平衡評估的重要性。
Self-Refine 的效果與基礎模型的能力密切相關。研究團隊使用 Vicuna-13B 模型進行的實驗揭示了一些關鍵洞察:
這一發現表明,Self-Refine 的效能與基礎模型的能力密切相關,特別是模型對指令的理解和執行能力。
理論學習固然重要,但實際動手實現 Self-Refine 可以讓我們更深入地理解這項技術。在這一部分,我們將使用 LangGraph 來實現 Self-Refine,並通過一個具體案例來展示整個過程。
首先,我們需要建立一個穩固的基礎架構。這包括導入必要的模組、設定 API 金鑰,以及初始化 ChatOpenAI 模型。
# 設定 OpenAI API 金鑰
os.environ["OPENAI_API_KEY"] = userdata.get('OPENAI_API_KEY')
# 初始化 ChatOpenAI
llm = ChatOpenAI(
temperature=0.7,
max_tokens=1024,
streaming=True
)
在此段程式碼中,我們首先導入所需的模組。其中,使用 ChatOpenAI
作為我們的語言模型,並設定其參數。temperature
設為 0.7,這提供了一個平衡點,既保留了一定的創造性,又不會過於發散。streaming=True
則允許我們即時獲取生成的內容。
📌 實用提示:確保所有環境變數都正確設置,這對於順利運行後續程式碼至關重要。
接下來,我們定義兩個核心模組:生成(REFINE)和反思(FEEDBACK)。這兩個模組構成了 Self-Refine 的基本循環。
# 生成模組(REFINE)
prompt = ChatPromptTemplate.from_messages([
("system", "您是一位專業的論文助理,擅長撰寫出色的五段式論文。"
"請為使用者的要求生成最佳論文。"
"如果使用者提供批評,請根據先前的嘗試提供修訂版本。"),
MessagesPlaceholder(variable_name="messages"),
])
generate = prompt | llm
essay = ""
request = HumanMessage(
content="請寫一篇論文,探討《哈利波特》在現代童年中的相關性"
)
for chunk in generate.stream({"messages": [request]}):
print(chunk.content, end="")
essay += chunk.content
# 反思模組(FEEDBACK)
reflection_prompt = ChatPromptTemplate.from_messages([
("system", "您是一位正在評分論文的老師。請為使用者的作品提供批評和建議。"
"提供詳細的建議,包括長度、深度、風格等方面的要求。"),
MessagesPlaceholder(variable_name="messages"),
])
reflect = reflection_prompt | llm
reflection = ""
for chunk in reflect.stream({"messages": [request, HumanMessage(content=essay)]}):
print(chunk.content, end="")
reflection += chunk.content
在這兩段程式碼中,我們定義了兩個不同的提示模板。生成模組負責創作內容,而反思模組則負責評估和提供改進建議。這種分離設計允許系統在不同階段專注於不同的任務,從而提高整體效能。MessagesPlaceholder
用於動態插入對話歷史,確保模型能夠根據上下文進行回應。
📌 小節摘要:
定義生成(REFINE)模組,負責內容創作
定義反思(FEEDBACK)模組,負責評估和提供建議
現在,我們設計 AI 的決策邏輯和狀態管理機制。這個機制決定了 AI 如何在生成和反思之間切換,以及何時結束迭代過程。
這邊開始就可以仰賴 LangGraph 協助完成。
class State(TypedDict):
messages: Annotated[List[BaseMessage], add_messages]
async def generation_node(state: State) -> State:
response = await generate.ainvoke(state["messages"])
return {"messages": state["messages"] + [AIMessage(content=response.content)]}
async def reflection_node(state: State) -> State:
cls_map = {"ai": HumanMessage, "human": AIMessage}
messages = state["messages"]
translated = [messages[0]] + [cls_map[msg.type](content=msg.content) for msg in messages[1:]]
res = await reflect.ainvoke({"messages": translated})
return {"messages": state["messages"] + [HumanMessage(content=res.content)]}
def should_continue(state: State) -> str:
if len(state["messages"]) > 6:
return END
return "reflect"
這段程式碼定義了系統的狀態結構和運作邏輯:
State
類別定義了系統狀態,主要包含消息歷史。generation_node
函數負責生成新內容,並將其添加到狀態中。reflection_node
函數負責反思和提供建議。注意這裡的消息類型轉換,這是為了模擬人類反饋。should_continue
函數決定是否繼續迭代。這裡設置了一個簡單的條件:當消息數量超過 6 時停止,這可以根據實際需求進行調整。📌 小節摘要:
- 定義狀態結構,用於追踪對話歷史
- 實現生成和反思節點,分別負責內容創作和評估
- 設計迭代終止條件,控制自我完善的次數
# 建構圖
builder = StateGraph(State)
builder.add_node("generate", generation_node)
builder.add_node("reflect", reflection_node)
builder.add_edge(START, "generate")
builder.add_conditional_edges("generate", should_continue)
builder.add_edge("reflect", "generate")
graph = builder.compile()
這段程式碼展示了如何構建和運行 Self-Refine 系統:
# 運行圖
async for event in graph.astream({"messages": [HumanMessage(content="生成一篇論文,探討《小王子》及其訊息在現代生活中的時代性")]}):
print(event)
print("---")
# 列印最終結果
import rich
rich.print(event['generate']['messages'][-1].content)
本章節詳細介紹了如何使用 LangGraph 實現 Self-Refine 技術,這是 LLM 自我優化的基礎技術。通過精心設計的生成和反思模組,以及靈活的狀態管理和決策邏輯,我們成功構建了一個能夠自我完善的 AI 系統。
Self-Refine 作為 LLM 反思機制的入門級實現,為更進階的技術如 Reflexion 奠定了重要基礎。Reflexion 在 Self-Refine 的基本原理上進行了創新和擴展,引入了更複雜的機制:
為了更全面地理解 LLM 的自我完善能力,我們建議讀者在學習完 Self-Refine 後,進一步探索 Reflexion 技術。在下一篇文章中,我們將深入探討 Reflexion 如何在 Self-Refine 的基礎上進一步提升 LLM 的自我完善能力,包括其創新的記憶機制和多步推理過程。
通過比較 Self-Refine 和 Reflexion,讀者將能夠更好地理解 LLM 反思機制的演進過程,以及這些技術如何推動 AI 系統向更高層次的智能發展。
即刻前往教學程式碼 Repo,親自動手體驗反思的威力吧!別忘了給專案按個星星並持續關注更新,讓我們一起探索AI代理的新境界。